﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Workflow.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Drawing2D;
using OpenComposite.Workflow.Interfaces;
using System.ComponentModel;
using System.Workflow.ComponentModel;
using System.Windows.Forms;
using System.ComponentModel.Design;
using System.Collections;
using OpenComposite.Workflow.Extenders;

namespace OpenComposite.Workflow
{
	public class ExtendedActivityDesigner : ActivityDesigner
	{
		#region Public Members

		#region Properties
		public override Size MinimumSize
		{
			get
			{
				return _sizeMinimum;
			}
		}
		public override string Text
		{
			get
			{
				ITextActivity textact = this.Activity as ITextActivity;
				if ( textact != null && !string.IsNullOrEmpty(textact.Text) ) {
					return textact.Text;
				} else {
					return base.Text;
				}
			}
			protected set
			{
				base.Text = value;
			}
		}
		#endregion

		#endregion

		#region Protected Members

		protected override void Initialize(Activity activity)
		{
			IExtenderListService extenderListService =
				(IExtenderListService)GetService(typeof(IExtenderListService));
			IExtenderProviderService extenderProviderService =
				(IExtenderProviderService)GetService(typeof(IExtenderProviderService));

			OutputVariableNameExtenderProvider.RegisterExtender(extenderListService, extenderProviderService);
			base.Initialize(activity);
		}

		#region Properties
		protected override Rectangle TextRectangle
		{
			get
			{
				if ( string.IsNullOrEmpty(this.Text) ) return Rectangle.Empty;

				AmbientTheme ambientTheme = WorkflowTheme.CurrentTheme.AmbientTheme;
				ActivityDesignerTheme designerTheme = this.DesignerTheme;
				Rectangle bounds = this.Bounds;
				Rectangle rectText = Rectangle.Empty;
				rectText.X =
					bounds.Left +
					ambientTheme.Margin.Width +
					( this.Image != null ?
						( designerTheme.ImageSize.Width + ambientTheme.Margin.Width ) : 0 );
				rectText.Y = bounds.Top + ( ( bounds.Height - _sizeText.Height ) / 2 );
				rectText.Size = _sizeText;
				return rectText;
			}
		}
		protected bool IsEditMode
		{
			get { return _isEditMode; }
		}
		TextEditorGlyph glyph = new TextEditorGlyph();
		protected override ActivityDesignerGlyphCollection Glyphs
		{
			get
			{
				return base.Glyphs;
			}
		}
		#endregion

		#region Methods
		protected override void OnActivityChanged(ActivityChangedEventArgs e)
		{
			base.OnActivityChanged(e);
			if ( e.Member != null && e.Member.Name != null && e.Member.Name.Equals("Text") ) {
				this.PerformLayout();
			}
		}
		protected override Size OnLayoutSize(ActivityDesignerLayoutEventArgs e)
		{
			_sizeText = WorkflowHelpers.MeasureString(e.Graphics, this.Text,
				e.DesignerTheme.BoldFont, StringAlignment.Center, _sizeMaxText);

			Size size = Size.Empty;
			size.Width =
				e.AmbientTheme.Margin.Width +
				( this.Image != null ?
					( e.DesignerTheme.ImageSize.Width + e.AmbientTheme.Margin.Width ) : 0 ) +
				_sizeText.Width +
				e.AmbientTheme.Margin.Width;
			size.Height =
				e.AmbientTheme.Margin.Height +
				Math.Max(e.DesignerTheme.ImageSize.Height, _sizeText.Height) +
				e.AmbientTheme.Margin.Height;

			return new Size(Math.Max(_sizeMinimum.Width, size.Width), Math.Max(_sizeMinimum.Height, size.Height));
		}
		protected override void OnPaint(ActivityDesignerPaintEventArgs e)
		{
			if ( e == null ) {
				throw new ArgumentNullException("e");
			}
			if ( Bounds != Rectangle.Empty ) {
				using ( GraphicsPath path = ActivityDesignerPaint.GetRoundedRectanglePath(this.Bounds, 8) ) {
					// fill background
					e.Graphics.FillPath(e.DesignerTheme.GetBackgroundBrush(this.Bounds), path);
					// draw border
					e.Graphics.DrawPath(e.DesignerTheme.BorderPen, path);
				}
				if ( !string.IsNullOrEmpty(this.Text) && !this.TextRectangle.Size.IsEmpty ) {
					ActivityDesignerPaint.DrawText(e.Graphics, e.DesignerTheme.Font, this.Text, this.TextRectangle,
						StringAlignment.Center, e.AmbientTheme.TextQuality, e.DesignerTheme.ForegroundBrush);
				}
				if ( this.Image != null && !this.ImageRectangle.Size.IsEmpty ) {
					ActivityDesignerPaint.DrawImage(e.Graphics, this.Image, this.ImageRectangle,
						DesignerContentAlignment.Fill);
				}
			}
			if ( _isEditMode ) {
				Point boxLoc = this.ParentView.LogicalPointToScreen(this.Location);
				boxLoc = new Point(boxLoc.X + 5, boxLoc.Y + 5);
				if ( _editBox == null || _editBox.IsDisposed ) {
					_editBox = new ActivityTextBox(this.Text, boxLoc);
					_editBox.VisibleChanged += new EventHandler(_editBox_VisibleChanged);
				}
				_editBox.Location = boxLoc;
				_editBox.BringToFront();
				try {
					_isEditMode = false;
					_editBox.TextBoxText = this.Text;
					if ( _editBox.ShowDialog() == System.Windows.Forms.DialogResult.OK ) {
						ITextActivity act = this.Activity as ITextActivity;
						if ( act != null ) {
							TypeDescriptor.GetProperties(act)["Text"].SetValue(act, _editBox.TextBoxText);
						}
						string identifier = WorkflowHelpers.EnsureUniqueName(this.Activity, cleanString(_editBox.TextBoxText));
						TypeDescriptor.GetProperties(act)["Name"].SetValue(act, identifier);
					}
				} catch { }

			}
		}
		protected override void DoDefaultAction()
		{
			if ( this.Activity is ExtendedCodeActivity && WorkflowView.ModifierKeys != System.Windows.Forms.Keys.Control ) {
				base.DoDefaultAction();
			} else {
				_isEditMode = true;
				this.Invalidate();
			}
		}

		protected override void OnDragOver(ActivityDragEventArgs e)
		{
			if ( e.Activities.Count == 1 ) {
				if ( root == null )
					root = WorkflowHelpers.GetRootDesigner(this) as HorizontalWorkflowDesigner;

				if ( e.Activities[0] is JumpSplitActivity ) {
					if ( root.DraggedActivity == null ) {
						e.Effect = DragDropEffects.None;
					} else {
						if ( this.ParentDesigner.Activity == e.Activities[0].Parent ||
							!WorkflowHelpers.HasInvalidJumpTarget(this) ) {
							e.Effect = DragDropEffects.Copy;
							setSelectedItem(this.Activity);
						} else {
							root.DraggedActivity = null;
							e.Effect = DragDropEffects.None;
						}
					}
				}
			}
			base.OnDragOver(e);
		}
		protected override void OnDragDrop(ActivityDragEventArgs e)
		{
			/* Jump START*/
			if ( e.Activities.Count == 1 ) {
				if ( root == null )
					root = WorkflowHelpers.GetRootDesigner(this) as HorizontalWorkflowDesigner;
				if ( e.Activities[0] is JumpSplitActivity && root != null ) {
					root.Workflow.WhileConnectors.Add(
						new FreeConnector(
							root.DraggedActivity.QualifiedName,
							this.Activity.QualifiedName));
					root.DraggedActivity = null;
					return;
				}
			}
			/* Jump END */
			base.OnDragDrop(e);
		}
		#endregion

		#endregion

		#region Private Members

		#region Methods
		ISelectionService _selectionService = null;
		private void setSelectedItem(object item)
		{
			setSelectedItem(item, SelectionTypes.Primary);
		}
		private void setSelectedItem(object item, SelectionTypes selectionType)
		{
			if ( _selectionService == null ) {
				_selectionService = GetService(typeof(ISelectionService)) as ISelectionService;
			}
			if ( _selectionService != null ) {
				ArrayList al = new ArrayList();
				if ( item != null )
					al.Add(item);
				_selectionService.SetSelectedComponents(al, selectionType);
			}
		}
		#endregion

		#region Fields
		private Size _sizeMaxText = new Size(135, 130);
		private Size _sizeText = new Size();
		private Size _sizeMinimum = new Size(50, 40);
		protected ActivityTextBox _editBox = null;
		private bool _isEditMode = false;
		private HorizontalWorkflowDesigner root = null;
		#endregion

		#region Event Handlers (Edit Box)
		void _editBox_VisibleChanged(object sender, EventArgs e)
		{
			//ITextActivity act = this.Activity as ITextActivity;
			//if ( act == null ) return;
			//TypeDescriptor.GetProperties(act)["Text"].SetValue(act, _editBox.TextBoxText);
			//TypeDescriptor.GetProperties(act)["Name"].SetValue(act, cleanString(_editBox.TextBoxText));
			////act.Text = _editBox.TextBoxText;
			//this.Invalidate();
		}

		private static List<char> _validIdentifierCharacters =
			new List<char>(new char[]{
				'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
				'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
				'1','2','3','4','5','6','7','8','9','0','_'
			});

		private string cleanString(string p)
		{
			string value = p;
			foreach ( char c in value ) {
				if ( !_validIdentifierCharacters.Contains(c) ) {
					value = value.Replace(c.ToString(), "");
				}
			}
			return value;
		}
		#endregion

		#endregion
	}

	public class TextEditorGlyph : DesignerGlyph
	{
		protected override void OnActivate(ActivityDesigner designer)
		{
			base.OnActivate(designer);
		}
		public override Rectangle GetBounds(ActivityDesigner designer, bool activated)
		{
			return designer.Bounds;
		}
		protected override void OnPaint(Graphics graphics, bool activated, AmbientTheme ambientTheme, ActivityDesigner designer)
		{
			graphics.DrawRectangle(Pens.Black, GetBounds(designer, activated));
		}
		public override bool CanBeActivated
		{
			get
			{
				return true;
			}
		}
	}
}
